import {Handler} from '@srcTypes/route';
import {Request, Response} from 'express';
import {tenantAppConfig} from '@srcConfig/config';
import {resp} from '@srcUtils/resp';
import {httpClient} from '@srcUtils/req';
import {
    doQueryTenantToken,
    getJsTicket,
    getToken,
    getTokenByAppId,
    saveUserInfo,
} from '@srcDb/redis/auth';
import {IAppTokenRes} from '@srcDb/redis/auth';
import {Buffer} from 'buffer';
import {User} from '@srcDb/model/user';
import {lark} from '@/config';
import {createDeflateRaw} from 'zlib';

const stringRandom = require('string-random');
const SHA1 = require('sha1');

/**
 * 同时更新 app_access_token, tenant_access_token,
 * 默认是我的 TEST 应用，查询参数 receive_type 判断是否存在用户传入的应用信息
 * input 表示用户输入的
 * app_id:
 * app_secret:
 * @param{Request} req
 * @param{Response} res
 */
export const getAppAccessTokenV2: Handler = async (req: Request, res: Response): Promise<IAppTokenRes> => {
    const receiveType = req.query.receive_type;
    // 默认后台设置
    let app_id: string = lark.env.appId;
    let app_secret: string = lark.env.appSecret;
    if (receiveType === 'input') {
        app_id = req.body.app_id as string;
        app_secret = req.body.app_secret as string;
    }
    const tenantToken: IAppTokenRes = await doQueryTenantToken({app_id, app_secret});
    // 隐私信息不传 只传 open_id union_id
    res.json(resp.setSuccess().setData(tenantToken).collect());
    return tenantToken;
};

/**
 * 只获取tenant_access_token
 * 暂时先不管 app token 可以同时获取到
 * @param{Request} req 请求上下文
 * @param{Response} res 响应上下文
 */
export const getTenantAccessTokenV2: Handler = async (req: Request, res: Response) => {
    const content = await httpClient.post({
        url: lark.env.api.AUTH_OPEN_API.TENANT_ACCESS_TOKEN_INTERNAL,
        requireToken: false,
        data: {
            'app_id': lark.env.appId,
            'app_secret': lark.env.appSecret,
        },
    }).catch((err: Error) => {
        res.json(resp.setCode(500).setMsg(err.message).setData({}).collect());
    });
    const contentData = content['data'];
    tenantAppConfig.tenantToken = contentData.tenant_access_token;
    res.json(resp.setCode(contentData.code).setSuccess().setData(content['data']).collect());
};
/**
 * 重定向url，转发到获取用户信息接口
 * @param{Request} req
 * @param{Response} res
 */
export const redirectUrlV2: Handler = async (req: Request, res: Response) => {
    const {code, state} = req.query;
    const stateParams = JSON.parse(Buffer.from(state as string, 'base64').toString('utf-8'));
    const {app_id} = stateParams;
    const appToken = await getTokenByAppId(app_id, 'A');
    // 自定义参数列表 key1=val1&key2=val2
    // 默认 tenantAppConfig 已经初始化，TODO 这块需要优化，保证每次请求都存在信息。初步构思：前端全部加权限校验，然后废弃该配置，只从 配置文件/db 获取
    const content = await httpClient.post({
        url: lark.env.api.AUTH_OPEN_API.AUTHEN_V1_ACCESS_TOKEN,
        requireToken: true,
        token: appToken,
        data: {
            'grant_type': 'authorization_code',
            'code': code,
        },
    }).catch((err: Error) => {
        res.json(resp.setCode(500).setMsg(err.message).setData({}).collect());
    });
    const authUserInfo: User = content['data'].data as User;
    await saveUserInfo(authUserInfo, stateParams['uuid']);
    // 重定向到模板携带 uuid
    res.redirect(`${stateParams['location']}?uuid=${stateParams['uuid']}&expires_in=${authUserInfo.expires_in}`);
};

/**
 * 获取jsapi_ticket
 * @param{Request} req
 * @param{Response} res
 */
export const getJsapiTicketV2: Handler = async (req: Request, res: Response) => {
    const auth = req.headers.authorization;
    const tenantToken = await getToken(auth, 'T', true);
    const ticketResp = await httpClient.post({
        url: lark.env.api.AUTH_OPEN_API.JSSDK_TICKET,
        requireToken: true,
        token: tenantToken,
    }).catch((err: Error) => {
        res.json(resp.setFail().collect());
    });
    const ticketData = ticketResp['data'];
    const {ticket} = ticketData['data'];
    return ticket;
};

/**
 * 鉴权 sdk以及云文档组件
 * 调用之前确保已经获取过token
 * @param{Request} req
 * @param{Response} res
 */
export const authenSdkV2: Handler = async (req: Request, res: Response) => {
    const ticket = await getJsapiTicketV2(req, res);
    const {url} = req.query;
    const nonceStr = stringRandom(16);
    const timestamp = new Date().getTime();
    let signature = `jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
    // eslint-disable-next-line new-cap
    signature = SHA1(signature);
    const obj = {
        'appId': lark.env.appId,
        'timestamp': timestamp,
        'nonceStr': nonceStr,
        'signature': signature,
    };
    console.log(obj);
    res.json(resp.setCode(0).setMsg('ok').setData(obj).collect());
};
/**
 * 清空应用信息等
 * @param{Request} req
 * @param{Response} res
 */
export const clearAppInfoV2: Handler = async (req: Request, res: Response) => {
    tenantAppConfig.clear();
    res.json(resp.setSuccess().collect());
};

/**
 * 调用之前确保已经获取过token
 * @param{Request} req
 * @param{Response} res
 */
export const authenDocSdkV2: Handler = async (req: Request, res: Response) => {
    const auth = req.headers.authorization;
    const {uuid, type, url} = req.body;
    const {ticket, open_id} = await getJsTicket(uuid, auth, type);
    const nonceStr = stringRandom(16);
    const timestamp = new Date().getTime();
    let signature = `jsapi_ticket=${ticket}&noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`;
    // eslint-disable-next-line new-cap
    signature = SHA1(signature);
    const obj = {
        'appId': lark.env.appId,
        'timestamp': timestamp,
        'nonceStr': nonceStr,
        'signature': signature,
        'url': url,
        'lang': 'zh',
        'openId': open_id,
    };
    console.log(obj);
    res.json(resp.setCode(0).setMsg('ok').setData(obj).collect());
};

export const qCodeAuth: Handler = async (req: Request, res: Response) => {
    const {tmp_code} = req.query;
    console.log(tmp_code);
    const params = {
        'grant_type': 'authorization_code',
        'client_id': lark.env.appId,
        'client_secret': lark.env.appSecret,
        'code': tmp_code,
        'redirect_uri': encodeURIComponent('https://baidu.com'),
    };
    const ret = await httpClient.post({
        url: 'https://passport.feishu.cn/suite/passport/oauth/token',
        requireToken: false,
        params,
    }).catch((err: Error) => {
        // console.log(err);
    });
    console.log((ret as any).data);
    res.json({
        msg: 'ok',
    });
};
